package algorithms;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class Common {

	public static List<List<String>> getAllSubsets(String[] input, int subSetsSize, Set<String> alphabetSet) {
		List<List<String>> result = new ArrayList<List<String>>();

		int size = input.length;

		if (subSetsSize > size)
			return null;

		if (subSetsSize == 1) {
			for (String string : input) {
				if (string == null || string.isEmpty()) {
					continue;
				}
				if (alphabetSet.contains(string)) {
					List<String> tmpV = new ArrayList<String>();
					tmpV.add(string);
					result.add(tmpV);
				}
			}
			return result;
		}
		String currentElement;
		List<List<String>> tmpListOfList;
		for (int i = 0; i < size - 1; i++) {
			currentElement = input[i];
			tmpListOfList = getSubsetsOfSize(Arrays.copyOfRange(input, i + 1, size), subSetsSize - 1, alphabetSet);
			if (tmpListOfList != null)
				for (List<String> list : tmpListOfList) {
					list.add(0, currentElement);
					result.add(list);
				}
		}

		return result;
	}

	public static List<List<String>> getSubsetsOfSize(String[] input, int subSetsSize, Set<String> alphabetSet) {
		List<List<String>> result = new ArrayList<List<String>>();

		int size = input.length;

		if (subSetsSize > size)
			return null;

		if (subSetsSize == 1) {
			for (String string : input) {
				if (string == null || string.isEmpty()) {
					continue;
				}
				if (alphabetSet.contains(string)) {
					List<String> tmpV = new ArrayList<String>();
					tmpV.add(string);
					result.add(tmpV);
				}
			}
			return result;
		}
		String currentElement;
		List<List<String>> tmpListOfList;
		for (int i = 0; i < size - 1; i++) {
			currentElement = input[i];
			tmpListOfList = getSubsetsOfSize(Arrays.copyOfRange(input, i + 1, size), subSetsSize - 1, alphabetSet);
			if (tmpListOfList != null)
				for (List<String> list : tmpListOfList) {
					list.add(0, currentElement);
					result.add(list);
				}
		}

		return result;
	}

	public static String[] parseLineToBasket(String line) {
		// Split
		String[] input = line.split(",");

		// Dedup and lower case
		Set<String> inputSet = new HashSet<String>();
		for (String string : input) {
			string = string.toLowerCase();
			inputSet.add(string);
		}
		input = new String[inputSet.size()];
		input = inputSet.toArray(input);
		return input;
	}

	public static Set<String> loadAlphabetSetFromInput(String filePathFormat, int fileStartIndex, int fileEndIndex,
			double support) throws Exception {
		BufferedReader br;
		String line;
		String[] tmpBasket;
		int numOfItems = 0;
		int numOfBaskets = 0;
		Map<String, Integer> singeltonsHistogram = new HashMap<String, Integer>();
		Set<String> result = new HashSet<String>();
		for (int i = fileStartIndex; i <= fileEndIndex; i++) {
			br = new BufferedReader(new FileReader(String.format(filePathFormat, i)));
			while ((line = br.readLine()) != null) {
				if (line.startsWith("#") || line.equals("")) {
					// Ignore comments
					continue;
				}
				line = line.toLowerCase();
				tmpBasket = line.split(",");
				// Update counters
				numOfItems += tmpBasket.length;
				numOfBaskets++;
				for (String word : tmpBasket) {
					if (singeltonsHistogram.containsKey(word)) {
						singeltonsHistogram.put(word, singeltonsHistogram.get(word) + 1);
					} else {
						singeltonsHistogram.put(word, 1);
					}
				}
			}
			br.close();
		}

		// Prune non common singletons
		int absSupport = (int) (support * numOfBaskets);
		for (Entry<String, Integer> entry : singeltonsHistogram.entrySet()) {
			if (entry.getValue() > absSupport) {
				result.add(entry.getKey());
			}
		}
		return result;
	}

	/**
	 * Load the alphabet file to memory - each line is a singleton element.
	 * 
	 * @throws Exception
	 */
	public static Set<String> loadAlphabetSetFromFile(String filePath) throws Exception {
		Set<String> result = new HashSet<String>();
		BufferedReader br;
		String line;
		br = new BufferedReader(new FileReader(filePath));
		while ((line = br.readLine()) != null) {
			result.add(line.toLowerCase());
		}
		br.close();
		return result;
	}

	public static void printStats(String pathFormat, double support, int numOfLines, Algo algo, long startMsec,
			List<String> result, long endMsec) {
		File file;
		PrintStream writer = null;
		try {
			file = new File(pathFormat + "." + algo + ".out.csv");
			writer = new PrintStream(file);
			printStats(writer, pathFormat, support, numOfLines, algo, startMsec, result, endMsec);
		} catch (Exception e) {
			return;
		}
	}

	public static void printStats(PrintStream writer, String runTitle, double support, int numOfLines, Algo algo,
			long startMsec, List<String> result, long endMsec) throws Exception {

		writer.println(" " + runTitle);
		writer.println(String.format(" Support=%f", support));
		writer.println(String.format(" Algo = %s", algo));
		writer.println(String.format(" Total time: %d milli sec", endMsec - startMsec));
		writer.println(String.format(" Total iterations = %d.", Algo.iterNum));
		writer.println(String.format(" Total items = %d.", algo.getNumOfItems()));
		writer.println(String.format(" Total baskets = %d.", algo.getNumOfBaskets()));
		writer.println(" size,apperences,items");
		Collections.sort(result);
		for (String string : result) {
			try {
				if (!string.startsWith(" ") && Integer.parseInt(string.split(",")[1]) < support * numOfLines) {
					continue;
				}
			} catch (Exception e) {
				continue;
			}
			writer.println(string);
		}
		writer.close();
		System.out.println(String.format("%s:\t%d iterations\t%d milliseconds", algo.toString(), Algo.iterNum, endMsec
				- startMsec));

	}
}
